import { RepoLink } from 'libframe-docs/components/RepoLink'

Environment: `Node.js`.

We use `createPageRenderer()` to create the server middlware that performs server-side rendering:

```js
// server.js
// Environment: Node.js server

// In this example we use Express.js but we could use any other server framework.
const express = require('express')
const { createPageRenderer } = require('vite-plugin-ssr')

const isProduction = process.env.NODE_ENV === 'production'
const root = `${__dirname}/..`
const base = '/'
const baseAssets = '/'
const outDir = `dist`

startServer()

async function startServer() {
  const app = express()

  let viteDevServer
  if (isProduction) {
    app.use(express.static(`${root}/${outDir}/client`))
  } else {
    const vite = require('vite')
    viteDevServer = await vite.createServer({
      root,
      server: { middlewareMode: 'ssr' }
    })
    app.use(viteDevServer.middlewares)
  }

  const renderPage = createPageRenderer({
    viteDevServer,
    isProduction,
    root,
    outDir,
    base,
    baseAssets
  })
  app.get('*', async (req, res, next) => {
    const url = req.originalUrl
    const pageContextInit = { url }
    const pageContext = await renderPage(pageContextInit)
    if (!pageContext.httpResponse) return next()
    const { body, statusCode, contentType } = pageContext.httpResponse
    res.status(statusCode).type(contentType).send(body)
  })

  const port = 3000
  app.listen(port)
  console.log(`Server running at http://localhost:${port}`)
}
```

- `viteDevServer` is the Vite dev server.
- `isProduction` is a boolean. When set to `true`, `vite-plugin-ssr` loads already-transpiled code from `dist/` instead of on-the-fly transpiling code.
- `root` is the absolute path of our app's root directory. The `root` directory is usually the directory where `vite.config.js` lives. All our `.page.js` files need to be descendent of the `root` directory.
- `outDir` is the build directory of your project. Default: `dist`.
- `base` is the [Base URL](/base-url).
- `baseAssets` is the [Base URL](/base-url) of our static assets.
- `pageContext.httpResponse` is `null` when a) an error occurred while rendering `_error.page.js`, or b) we didn't define the page `_error.page.js` and and an error occured.
- `pageContext.httpResponse.statusCode` is either `200`, `404`, or `500`.
- `pageContext.httpResponse.contentType` is either `text/html` or `application/json`. (The Content Type is `application/json` when [Client Routing](/useClientRouter) fetches the `pageContext` of the newly navigated page.)
- `pageContext.httpResponse.body` is the HTML-sanitized string returned by the `render()` hook with added assets that `vite-plugin-ssr` automatically injected.

Since `createPageRenderer()` and `renderPage()` are agnostic to Express.js, we can use `vite-plugin-ssr` with any server framework (Koa, Hapi, Fastify, vanilla Node.js, ...) and any deploy environment such as Cloudflare Workers or Vercel.

Examples:
 - <RepoLink text='JavaScript' path='/boilerplates/boilerplate-vue/server/index.js' />
 - <RepoLink text='TypeScript' path='/boilerplates/boilerplate-vue-ts/server/index.ts' />
